library(readxl)
library(tidyverse)
library(gt)Der Datensatz “Kosten des Gesundheitswesens nach Leistungen” wird vom Bundesamt für Statistik (BFS) publiziert als MS Excel Datei hier publiziert. Die Daten wurden zuletzt am 31.10.2020 für das Jahr 2018 aktualisiert. Diese und weitere Metadaten sind in der MS Excel Datei ab Reihe 44 zu finden.
Wir importieren die Datei in dem wir sie mit der Funkion download.file() herunterladen und in dem Ordner “data/raw” innerhalb unseres Projektes speichern. Die URL bezieht sich direkt auf den Download Link. Danach können wir die Daten mit der Funktion read_excel() in unsere Arbeitsumgebung importieren.
R Package {here}
Das R Package mit dem Namen here ist sehr hilfreich im Umgang mit Dateipfaden. Wenn wir in den File Manager unten rechts blicken sehen wir in diesem RStudio Project zwei Ordner:
Die Daten für das Projekt stecken im Ordner ‘data’. Die R Markdown Datei für die Analyse steckt im Ordner ‘analyse’. Um die Daten aus dem Ordner ‘data’ zu lesen, müssen die Dateipfade korrekt gesetzt sein. Standardmässig ist der aktuelle Pfad in R Markdown Dateien der Pfad an dem die Datei gespeichert ist, und nicht der Stammpfad des Projektes. Sobald eine R Markdown Datei und die zu importierenden Daten nicht am gleichen Ort liegen, müssen die Pfade angepasst werden.
Pfade unterscheiden sich zwischen Arbeitsgeräten, weshalb es sich nicht empfiehlt einen absoluten Pfad zu setzen, zum Beispiel:
read_excel(/Users/work/gitrepos/teaching-starter/demonstration/demo-03-tabellen/data/raw/je-d-14.05.01.03.xlsx)"Dieses Skript würde nur auf diesem einen Arbeitsgerät problemlos und der Pfad müsste jeweils angepasst werden. Das here Package löst diese Problem mit der Funktion des selben Namen here(), welche den Pfad in der jeweiligen Arbeitsumgebung korrekt setzt.
library(readxl) # https://readxl.tidyverse.org/
library(here)
# was sehen wir?
download.file(url = "https://www.bfs.admin.ch/bfsstatic/dam/assets/14840808/master",
destfile = here("data/raw/je-d-14.05.01.03.xlsx"))
gesundheit <- read_excel(path = here("data/raw/je-d-14.05.01.03.xlsx"),
skip = 2,
n_max = 44)Hier ist der Code zum Daten aufräumen (Data tidying) bereits geschrieben. Der Code ist als eine lange Code Sequenz geschrieben, in welcher jeder Schritt kommentiert ist. Neu tauchen hier zwei Funktionen aus dem stringr Package auf, welches das Arbeiten mit Text unterstützt:
str_length()str_replace()Um mehr über das Arbeiten mit Text in R zu lernen, siehe hier:
# Starte mit Objekt gesundheit und speicher das Ergebnis als ein Objekt mit dem
# Namen gesundheit_total in deiner Arbeitsumgebung
gesundheit_total <- gesundheit %>%
# Entferne die erste Zeile
slice(-1) %>%
# Geben den ersten beiden Spalten einen neuen Namen
rename(kategorie_code = ...1,
kategorie_name = ...2) %>%
# Filter alle Werte in der Spalte "kategorie_code", bei welchen die Länge des
# Textes (string) gleich 1 ist
filter(str_length(kategorie_code) == 1) %>%
# Bringe die Daten von einem weiten in ein langes Format
pivot_longer(cols = !c(kategorie_code, kategorie_name), # drehe alle bis auf diese zwei Spalten
names_to = "jahr", # Speicher die Namen in neuer Spalte "jahr"
values_to = "mio_chf") %>% # Speicher die Werte in neuer Spalgte "mio_chf"
# Mache eine Typumwandlung von character Variable auf numerische Varibale
mutate(jahr = as.numeric(jahr)) %>%
# Ersetze Text mit einer Zahl und geschlossenen Klammer ')' durch leeren Text
mutate(kategorie_name = str_replace(string = kategorie_name,
# Regular Expression pattern für eine Zahl (d) und die Klammer )
pattern = " \\d\\)",
replacement = ""))
# Erstelle einen Tibble für den Code und Namen der Leistungskategorien
leistungen <- gesundheit_total %>%
select(kategorie_code, kategorie_name) %>%
# Die Funktion distinct stammt aus dem dplyr Package und bewirkt das in einem
# Datensatz nur eindeutige Reihen auftauchen (keine Wiederholungen)
distinct()In diesem Code Chunk sind die einzelnen Schritte zum Säubern von Daten in Untrschritte unterteilt. Dies hilft dabei jeden Schritt als ein einziges kleines Problem anzugehen und unterstützt auch bei einer möglichen Fehlersuche.
# Schritt 1
ges1 <- gesundheit %>%
slice(-1) %>%
rename(sparte_code = ...1,
sparte_name = ...2)
# Schritt 2
ges2 <- ges1 %>%
mutate(kategorie_code = case_when(
str_length(sparte_code) == 1 ~ sparte_code,
TRUE ~ NA_character_
))
# Schritt 3
ges3 <- ges2 %>%
relocate(kategorie_code) %>%
fill(kategorie_code)
# Schritt 4
ges4 <- ges3 %>%
filter(str_length(sparte_code) > 1)
# Schritt 5
ges5 <- ges4 %>%
pivot_longer(cols = !kategorie_code:sparte_name,
names_to = "jahr",
values_to = "mio_chf",
values_drop_na = TRUE) %>%
mutate(jahr = as.numeric(jahr))
# Schritt 6
ges6 <- ges5 %>%
left_join(leistungen)
# Schritt 7
ges7 <- ges6 %>%
mutate(sparte_name = str_replace(string = sparte_name,
# Regular Expression pattern für eine Zahl (d) und die Klammer )
pattern = " \\d\\)",
replacement = ""))
# Schritt 8
gesundheit_tidy_ab2010 <- ges7 %>%
relocate(kategorie_name, .after = "kategorie_code")In der original MS Excel Tabelle sind einige Leistungen mit Fussnoten versehen. Diese Zahlen für die Fussnoten tauchen auch wieder auf wenn die Daten importiert werden, jeoch erfüllen sie nicht mehr ihren Zweck, da die eigentlichen Fussnoten fehlen. Die Funktion str_replace() ersetzt die Fussnoten mit einem leeren Text. Über die Funktione str_detect() können Spalten nach bestimmten Text Kriterien gefiltert werden. Im folgenden Code-chunk ist dies für drei Beispiele dokumentiert.
# Was passiert in Schritt 7?
# Beispiel 1
# Regular expressions- Ein fortgeschrittenes Thema
# Filter die Spalter sparte_name nach allen Werten welche dem Muster "\\d\\)"
# Zum Bespiel: 1)
# Mit \d wird eine Zahl identifiziert. Der zweite Backslash erstellt eine
# "Escapezeichenfolge" und ist notwendig um das \d nicht als Text zu deuten
# Mit \\) wird das Zeichen ) identifiziert
ges6 %>%
filter(str_detect(string = sparte_name,
# Regular Expression Muster für eine Zahl (d) und die Klammer )
pattern = "\\d\\)"))
# Beispiel 2
# Filter über die Länge eine strings (Texts)
# Filter die Spalter sparte_code nach Text welcher länger ist als ein Zeichen
# Zum Beispiel L1
ges1 %>%
filter(str_length(sparte_code) > 1)
# Beispiel 3
# Filter über einen Teil des Textes
# Filter die Spalte kategorie_name nach Text welcher den String 'pflege'
# enthält
gesundheit_total %>%
filter(str_detect(kategorie_name, "pflege"))library(plotly)
plot_gesundheit_total <- gesundheit_total %>%
mutate(mio_chf = round(mio_chf, 0)) %>%
# Plot mit ggplot erstellen
ggplot(aes(x = jahr, y = mio_chf, color = kategorie_name)) +
geom_point() +
geom_path() +
scale_color_brewer(type = "qual") +
labs(title = "Kosten des Gesundheitswesens nach Leistungen \nSchweiz, National, 1995 bis 2018",
x = "Jahr",
y = "Millionen Franken [CHF]",
color = "Leistung") +
theme_minimal()
ggplotly(plot_gesundheit_total)Für Alle die mehr lernen wollen: https://plotly-r.com/index.html
{gt} Package# Daten eingrenzen
gesundheit_sparte_tab <- gesundheit_tidy_ab2010 %>%
select(-ends_with("code")) %>%
pivot_wider(names_from = "jahr", values_from = "mio_chf")
# Variablen Namen der Jahreszahlen speichern
jahr_var <- gesundheit_sparte_tab %>%
select(`2010`:`2018`) %>%
names()# Tabelle darstellen
# Schritt 1
gesundheit_sparte_tab %>%
gt(rowname_col = "sparte_name",
groupname_col = "kategorie_name") %>%
tab_header(title = "Kosten des Gesundheitswesens nach Leistungen 2010 bis 2018") %>%
tab_spanner(label = "In Millionen Franken",
columns = vars(jahr_var)) %>%
fmt_number(columns = vars(jahr_var),
decimals = 0,
sep_mark = " ") %>%
tab_source_note(source_note = md("**Quelle:** Bundesamt für Statistik (BFS) –
Kosten und Finanzierung des Gesundheitswesens")) %>%
tab_source_note(source_note = md("**Datenbezug:**
[opendata.swiss](https://opendata.swiss/de/dataset/kosten-des-gesundheitswesens-nach-leistungen6)")) %>%
tab_footnote(footnote = "Neuberechnung ab 2010. Retropolation auf Basis bisheriger Wachstumsraten für die Jahre 1995-2009.",
locations = cells_title()) %>%
summary_rows(groups = TRUE,
columns = jahr_var,
fns = list(Summe = "sum"),
formatter = fmt_number,
decimals = 0,
sep_mark = " ") %>%
grand_summary_rows(columns = jahr_var,
fns = list(Total = "sum"),
formatter = fmt_number,
decimals = 0,
sep_mark = " ") %>%
tab_options(
row_group.background.color = "#E4E7F6",
summary_row.background.color = "#DCDCDC",
grand_summary_row.background.color = "#808080",
)| Kosten des Gesundheitswesens nach Leistungen 2010 bis 20181 | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| In Millionen Franken | |||||||||
| 2010 | 2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 | 2018 | |
| Stationäre Kurativbehandlung | |||||||||
| Stationäre somatische Akutbehandlung | 11 696 | 11 878 | 12 397 | 12 946 | 13 118 | 13 469 | 13 832 | 13 786 | 13 622 |
| Stationäre Psychiatriebehandlung | 1 674 | 1 699 | 1 771 | 1 836 | 1 819 | 1 905 | 1 912 | 1 917 | 1 908 |
| Stationäre Geburtshausbehandlung | 3 | 5 | 8 | 9 | 10 | 12 | 14 | 16 | 17 |
| Summe | 13 373 | 13 583 | 14 176 | 14 791 | 14 947 | 15 386 | 15 758 | 15 718 | 15 548 |
| Ambulante Kurativbehandlung | |||||||||
| Ambulante somatische Akutbehandlung im Spital | 4 226 | 4 315 | 4 717 | 4 969 | 5 427 | 5 677 | 6 136 | 6 307 | 6 409 |
| Ärztliche Behandlung, ambulant, Einzelleistungen | 4 509 | 4 317 | 4 273 | 4 343 | 4 405 | 4 638 | 4 711 | 4 690 | 3 871 |
| Ärztliche Behandlung, ambulant, Managed Care | 1 582 | 1 984 | 2 277 | 2 578 | 2 839 | 3 195 | 3 400 | 3 659 | 3 797 |
| Zahnbehandlung | 4 022 | 4 089 | 4 171 | 4 251 | 4 347 | 4 279 | 4 256 | 4 473 | 4 684 |
| Ambulante Psychiatrie- und Psychologiebehandlung, kurativ | 864 | 854 | 923 | 987 | 1 121 | 1 169 | 1 263 | 1 301 | 1 391 |
| Ambulante Geburtshilfe, ambulante Geburtshausbehandlung | 53 | 58 | 61 | 65 | 73 | 84 | 106 | 116 | 125 |
| Andere kurative Therapien | 552 | 491 | 503 | 496 | 468 | 500 | 566 | 563 | 477 |
| Summe | 15 808 | 16 109 | 16 924 | 17 688 | 18 681 | 19 541 | 20 436 | 21 108 | 20 753 |
| Rehabilitation | |||||||||
| Stationäre Rehabilitation | 1 692 | 1 698 | 1 695 | 1 719 | 1 678 | 1 817 | 1 833 | 1 834 | 1 892 |
| Ambulante Rehabilitation, nicht-psychosomatisch | 1 071 | 1 090 | 1 138 | 1 206 | 1 401 | 1 561 | 1 728 | 1 829 | 1 931 |
| Summe | 2 764 | 2 789 | 2 834 | 2 925 | 3 080 | 3 378 | 3 560 | 3 663 | 3 823 |
| Langzeitpflege | |||||||||
| Langzeitpflege in Institutionen | 10 952 | 11 491 | 11 950 | 12 264 | 12 548 | 12 873 | 13 031 | 13 376 | 13 674 |
| Häusliche Langzeitpflege, engerer Sinn: Pflege | 1 637 | 1 765 | 1 882 | 1 991 | 2 080 | 2 257 | 2 417 | 2 566 | 2 700 |
| Häusliche Langzeitpflege, weiterer Sinn: Haushalt etc. | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
| Summe | 12 589 | 13 257 | 13 832 | 14 255 | 14 628 | 15 129 | 15 449 | 15 943 | 16 374 |
| Unterstützende Dienstleistungen | |||||||||
| Laboranalysen | 1 025 | 1 103 | 1 131 | 1 319 | 1 455 | 1 559 | 1 717 | 1 871 | 1 939 |
| Transport und Rettung | 304 | 334 | 346 | 401 | 406 | 438 | 465 | 460 | 476 |
| Radiologie | 766 | 799 | 843 | 951 | 1 040 | 1 061 | 1 110 | 1 132 | 993 |
| Gemeinwirtschaftliche Leistung: Lehre und Forschung | 754 | 736 | 852 | 931 | 925 | 986 | 1 125 | 1 159 | 1 237 |
| Gemeinwirtschaftliche Leistung: Sonstige | 473 | 745 | 793 | 812 | 940 | 994 | 1 136 | 1 406 | 1 544 |
| Summe | 3 322 | 3 717 | 3 966 | 4 414 | 4 767 | 5 037 | 5 553 | 6 028 | 6 188 |
| Gesundheitsgüter | |||||||||
| Medikamente, stationär | 572 | 556 | 520 | 518 | 478 | 503 | 507 | 511 | 531 |
| Medikamente, ambulant, verschreibungspflichtig | 5 399 | 5 490 | 5 632 | 5 702 | 5 801 | 6 106 | 6 508 | 6 907 | 6 860 |
| Medikamente, ambulant, frei verkäuflich | 1 664 | 1 678 | 1 695 | 1 777 | 1 789 | 1 900 | 2 030 | 1 999 | 2 078 |
| Verbrauchsprodukte | 635 | 635 | 651 | 679 | 704 | 696 | 700 | 672 | 763 |
| Therapeutische Apparate | 1 814 | 1 739 | 1 682 | 1 743 | 1 831 | 1 894 | 1 957 | 2 000 | 1 981 |
| Summe | 10 083 | 10 098 | 10 181 | 10 419 | 10 604 | 11 100 | 11 702 | 12 088 | 12 214 |
| Prävention | |||||||||
| Primärprävention: Sucht | 287 | 270 | 278 | 320 | 313 | 330 | 308 | 322 | 440 |
| Primärprävention: Psychische Gesundheit, Schulgesundheit | 184 | 179 | 173 | 173 | 171 | 167 | 181 | 183 | 182 |
| Primärprävention: Unfälle und Verletzungen | 120 | 138 | 130 | 130 | 128 | 129 | 128 | 121 | 137 |
| Primärprävention: Lebensmittelsicherheit | 172 | 171 | 169 | 170 | 175 | 180 | 188 | 157 | 152 |
| Primärprävention: Aufklärung der Bevölkerung/Zielgruppen | 193 | 171 | 169 | 170 | 173 | 173 | 186 | 233 | 267 |
| andere Prävention | 751 | 766 | 781 | 818 | 891 | 897 | 904 | 921 | 948 |
| Summe | 1 707 | 1 696 | 1 700 | 1 781 | 1 852 | 1 878 | 1 894 | 1 937 | 2 126 |
| Verwaltung | |||||||||
| Verwaltung öffentliches Gesundheitswesen | 494 | 509 | 495 | 497 | 477 | 473 | 493 | 515 | 522 |
| Verwaltung Sozialversicherungen | 1 579 | 1 658 | 1 739 | 1 790 | 1 809 | 1 832 | 1 942 | 1 961 | 1 952 |
| Verwaltung Privatversicherungen | 845 | 830 | 665 | 558 | 584 | 630 | 668 | 681 | 742 |
| Summe | 2 918 | 2 996 | 2 899 | 2 845 | 2 870 | 2 935 | 3 103 | 3 157 | 3 216 |
| Total | 62 565 | 64 243 | 66 512 | 69 118 | 71 429 | 74 385 | 77 455 | 79 643 | 80 242 |
| Quelle: Bundesamt für Statistik (BFS) – Kosten und Finanzierung des Gesundheitswesens | |||||||||
| Datenbezug: opendata.swiss | |||||||||
|
1
Neuberechnung ab 2010. Retropolation auf Basis bisheriger Wachstumsraten für die Jahre 1995-2009.
|
|||||||||